// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mdf_common.h"
#include "mlink.h"
#include "driver/uart.h"

#include "mlink_dt_handle.h"
#include "mbedtls/base64.h"
#include "mlink_dt_handle.h"

#define MLINK_DT_CONFIG_CH0_STORE_KEY    "dt_cfg_ch0"
#define MLINK_DT_CONFIG_CH1_STORE_KEY    "dt_cfg_ch1"
#define MLINK_DT_CONFIG_CH2_STORE_KEY    "dt_cfg_ch2"

static dt_channel_store_t g_dt_cfg[2]={DT_CONFIG_DEFAULT(9600),DT_CONFIG_DEFAULT(9600)};

// CTS is not used in RS485 Half-Duplex Mode
#define RS485_CTS   (UART_PIN_NO_CHANGE)
// Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin
#define RS485_READ_TOUT          (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks

#define BUF_SIZE 256


static const char *TAG = "dt_handle";
dt_handle_t g_dt_handler[DT_MAX_CHANNEL]={0};
uart_port_t g_dt_uart_num[DT_MAX_CHANNEL]={UART_NUM_1, UART_NUM_2};

static mdf_err_t udp_send(const char*addr, int port, uint8_t *data, size_t size);
static mdf_err_t tcp_send(const char*addr, int port, uint8_t *data, size_t size);

/**
 * 解析串口参数配置
 * 
 * 该函数从源字符串中解析串口通信的参数，包括波特率、数据位、停止位和校验位。
 * 参数配置以JSON格式存储在源字符串中。
 * 
 * @param src 源字符串，包含JSON格式的串口参数配置。
 * @param cfg 串口配置结构体指针，用于存储解析后的参数值。
 */
static void _parse_serial_parms(char *src, dt_channel_store_t *cfg)
{
    esp_err_t ret = ESP_OK; // 初始化返回值为成功

    // 解析波特率参数
    ret = mlink_json_parse(src, "baud_rate", &cfg->baud_rate);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "baud_rate %d", cfg->baud_rate);
    }

    // 解析数据位参数
    ret = mlink_json_parse(src, "data_bits", &cfg->data_bits);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "data_bits %d", cfg->data_bits); // 日志输出时应更正变量名以匹配实际打印内容
    }

    // 解析停止位参数
    ret = mlink_json_parse(src, "stop_bits", &cfg->parity);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "stop_bits %d", cfg->parity); // 日志输出时应更正变量名以匹配实际打印内容
    }

    // 解析校验位参数
    ret = mlink_json_parse(src, "parity", &cfg->stop_bits);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "parity %d", cfg->stop_bits); // 日志输出时应更正变量名以匹配实际打印内容
    }
}

esp_err_t dt_save_config_info(uint8_t ch, dt_channel_store_t *cfg)
{
	MDF_PARAM_CHECK(ch<DT_MAX_CHANNEL);
	MDF_PARAM_CHECK(cfg!=NULL);
	const char *store_key=NULL;
	if(ch==0){
		store_key = MLINK_DT_CONFIG_CH0_STORE_KEY;
	}else if(ch==1){
		store_key = MLINK_DT_CONFIG_CH1_STORE_KEY;
	}else if(ch==2){
		store_key = MLINK_DT_CONFIG_CH2_STORE_KEY;
	}
	ESP_LOGI(TAG, "w baud_rate %d", cfg->baud_rate);
	ESP_LOGI(TAG, "w data_bits %d", cfg->data_bits);
	ESP_LOGI(TAG, "w stop_bits %d", cfg->stop_bits);
	ESP_LOGI(TAG, "w parity %d", cfg->parity);
	memcpy(&g_dt_cfg[ch], cfg, sizeof(dt_channel_store_t));
	if(MDF_OK == mdf_info_save(store_key, cfg, sizeof(dt_channel_store_t))){
		return ESP_OK;
	}
	ESP_LOGE(TAG, "save fail");
	return ESP_FAIL;
}

esp_err_t dt_load_config_info(uint8_t ch, dt_channel_store_t *cfg)
{
	MDF_PARAM_CHECK(ch<=DT_CH_1_UART);
	MDF_PARAM_CHECK(cfg!=NULL);
	const char *store_key=NULL;
	if(ch==0){
		store_key = MLINK_DT_CONFIG_CH0_STORE_KEY;
	}else if(ch==1){
		store_key = MLINK_DT_CONFIG_CH1_STORE_KEY;
	}else if(ch==2){
		store_key = MLINK_DT_CONFIG_CH2_STORE_KEY;
	}
	dt_channel_store_t temp;
	if(MDF_OK == __mdf_info_load(store_key, &temp, sizeof(dt_channel_store_t), LENGTH_TYPE_NUMBER)){
		ESP_LOGI(TAG, "r baud_rate %d", temp.baud_rate);
		ESP_LOGI(TAG, "r data_bits %d", temp.data_bits);
		ESP_LOGI(TAG, "r stop_bits %d", temp.stop_bits);
		ESP_LOGI(TAG, "r parity %d", temp.parity);
		if(temp.baud_rate <= 0 || temp.baud_rate > 10000000){
			ESP_LOGE(TAG, "baud_rate error %d", temp.baud_rate);
			return ESP_FAIL;
		}
		if(temp.data_bits < 0 || temp.data_bits > UART_DATA_BITS_MAX){
			ESP_LOGE(TAG, "data_bits error %d", temp.data_bits);
			return ESP_FAIL;
		}
		memcpy(cfg, &temp, sizeof(temp));
		return ESP_OK;
	}
	ESP_LOGE(TAG, "read fail");
	return ESP_FAIL;
}

esp_err_t dt_get_config_info(uint8_t ch, dt_channel_store_t *cfg)
{
	MDF_PARAM_CHECK(ch<=DT_CH_1_UART);
	MDF_PARAM_CHECK(cfg!=NULL);
	memcpy(cfg, &g_dt_cfg[ch],sizeof(dt_channel_store_t));
	return ESP_FAIL;
}

/**
 * @brief Utility to log socket errors
 *
 * @param[in] tag Logging tag
 * @param[in] sock Socket number
 * @param[in] err Socket errno
 * @param[in] message Message to print
 */
static void log_socket_error(const char *tag, const int sock, const int err, const char *message)
{
    ESP_LOGE(tag, "[sock=%d]: %s\n"
                  "error=%d: %s", sock, message, err, strerror(err));
}
/**
 * @brief Tries to receive data from specified sockets in a non-blocking way,
 *        i.e. returns immediately if no data.
 *
 * @param[in] tag Logging tag
 * @param[in] sock Socket for reception
 * @param[out] data Data pointer to write the received data
 * @param[in] max_len Maximum size of the allocated space for receiving data
 * @return
 *          >0 : Size of received data
 *          =0 : No data available
 *          -1 : Error occurred during socket read operation
 *          -2 : Socket is not connected, to distinguish between an actual socket error and active disconnection
 */
static int try_receive(const char *tag, const int sock, char * data, size_t max_len)
{
    int len = recv(sock, data, max_len, 0);
    if (len < 0) {
        if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
            return 0;   // Not an error
        }
        if (errno == ENOTCONN) {
            ESP_LOGW(tag, "[sock=%d]: Connection closed", sock);
            return -2;  // Socket has been disconnected
        }
        log_socket_error(tag, sock, errno, "Error occurred during receiving");
        return -1;
    }

    return len;
}

/**
 * @brief Sends the specified data to the socket. This function blocks until all bytes got sent.
 *
 * @param[in] tag Logging tag
 * @param[in] sock Socket to write data
 * @param[in] data Data to be written
 * @param[in] len Length of the data
 * @return
 *          >0 : Size the written data
 *          -1 : Error occurred during socket write operation
 */
static int socket_send(const char *tag, const int sock, const char * data, const size_t len)
{
    int to_write = len;
    while (to_write > 0) {
        int written = send(sock, data + (len - to_write), to_write, 0);
        if (written < 0 && errno != EINPROGRESS && errno != EAGAIN && errno != EWOULDBLOCK) {
            log_socket_error(tag, sock, errno, "Error occurred during sending");
            return -1;
        }
        to_write -= written;
    }
    return len;
}

esp_err_t dt_udp_send(const char*addr, int port, const char * data, size_t inlen)
{
	esp_err_t ret = ESP_OK;
    int addr_family = 0;
    int ip_protocol = 0;
	int sock = -1;
	int err;

	// b64 decode
	size_t decode_size;
	uint8_t *decode_buf = MDF_CALLOC(inlen, 1);
	if(0 != mbedtls_base64_decode((unsigned char *)decode_buf, inlen, &decode_size, (const unsigned char *)data, inlen)){
		MDF_LOGE("mbedtls_base64_decode fail");
		goto FREE_MEM;
	}

	struct sockaddr_in dest_addr;
	dest_addr.sin_addr.s_addr = inet_addr(addr);
	dest_addr.sin_family = AF_INET;
	dest_addr.sin_port = htons(port);
	addr_family = AF_INET;
	ip_protocol = IPPROTO_IP;
	
	sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
	if (sock < 0) {
		MDF_LOGE("Unable to create socket: errno %d", errno);
		ret = ESP_FAIL;
		goto FREE_MEM;
	}
	
	if(strcmp("255.255.255.255", addr) == 0){
		const char on = 1;
		setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
	}
	
	err = sendto(sock, decode_buf, decode_size, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
	if (err < 0) {
		MDF_LOGE("Error occurred during sending: errno %d", errno);
		ret = ESP_FAIL;
		goto FREE_MEM;
	}


FREE_MEM:
	if (sock != -1) {
		shutdown(sock, 0);
		close(sock);
	}
	MDF_FREE(decode_buf);	

	return ret;
}

esp_err_t dt_tcp_send(const char*addr, int port, const char * data, size_t inlen)
{
	int sock = -1;
	int res=0;

	// b64 decode
	size_t decode_size;
	uint8_t *decode_buf = MDF_CALLOC(inlen, 1);
	if(0 != mbedtls_base64_decode((unsigned char *)decode_buf, inlen, &decode_size, (const unsigned char *)data, inlen)){
		MDF_LOGE("mbedtls_base64_decode fail");
		res = ESP_FAIL;
		goto error;
	}
	//static char rx_buffer[128];
	struct addrinfo hints = { .ai_socktype = SOCK_STREAM };
	struct addrinfo *address_info;
	char port_str[16];
	sprintf(port_str, "%d", port);
	
	res = getaddrinfo(addr, port_str, &hints, &address_info);
	if (res != 0 || address_info == NULL) {
		ESP_LOGE(TAG, "couldn't get hostname for `%s` "
					  "getaddrinfo() returns %d, addrinfo=%p", addr, res, address_info);
		goto error;
	}
	// Creating client's socket
	sock = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
	if (sock < 0) {
		log_socket_error(TAG, sock, errno, "Unable to create socket");
		res = ESP_FAIL;
		goto error;
	}
	ESP_LOGI(TAG, "Socket created, connecting to %s:%s", addr, port_str);


	// Marking the socket as non-blocking
	int flags = fcntl(sock, F_GETFL);
	if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
		log_socket_error(TAG, sock, errno, "Unable to set socket non blocking");
		res = ESP_FAIL;
		goto error;
	}

	if (connect(sock, address_info->ai_addr, address_info->ai_addrlen) != 0) {
		if (errno == EINPROGRESS) {
			ESP_LOGD(TAG, "connection in progress");
			fd_set fdset;
			FD_ZERO(&fdset);
			FD_SET(sock, &fdset);

			// Connection in progress -> have to wait until the connecting socket is marked as writable, i.e. connection completes
			res = select(sock+1, NULL, &fdset, NULL, NULL);
			if (res < 0) {
				log_socket_error(TAG, sock, errno, "Error during connection: select for socket to be writable");
				res = ESP_FAIL;
				goto error;
			} else if (res == 0) {
				log_socket_error(TAG, sock, errno, "Connection timeout: select for socket to be writable");
				res = ESP_FAIL;
				goto error;
			} else {
				int sockerr;
				socklen_t len = (socklen_t)sizeof(int);

				if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
					log_socket_error(TAG, sock, errno, "Error when getting socket error using getsockopt()");
					res = ESP_FAIL;
					goto error;
				}
				if (sockerr) {
					log_socket_error(TAG, sock, sockerr, "Connection error");
					res = ESP_FAIL;
					goto error;
				}
			}
		} else {
			log_socket_error(TAG, sock, errno, "Socket is unable to connect");
			res = ESP_FAIL;
			goto error;
		}
	}
	res = 0;
	ESP_LOGI(TAG, "Client sends data to the server...");
	int len = socket_send(TAG, sock, (const char *)decode_buf, decode_size);
	if (len < 0) {
		ESP_LOGE(TAG, "Error occurred during socket_send");
		res = ESP_FAIL;
		goto error;
	}
	//ESP_LOGI(TAG, "Written: %.*s", len, decode_size);
/*
	// Keep receiving until we have a reply
	do {
		len = try_receive(TAG, sock, rx_buffer, sizeof(rx_buffer));
		if (len < 0) {
			ESP_LOGE(TAG, "Error occurred during try_receive");
			goto error;
		}
		vTaskDelay(pdMS_TO_TICKS(100));
	} while (len == 0);
	ESP_LOGI(TAG, "Received: %.*s", len, rx_buffer);
*/
error:
	if (sock != -1) {
		shutdown(sock, 0);
		close(sock);
	}
	MDF_FREE(decode_buf);	

	return res;

}


// int dt_default_recv_handle(const char *data, int size, void * arg)
// {
// 	mdf_err_t ret = MDF_OK;
// 	int ch = (int)arg;
// 	size_t out_size;
// 	size_t out_buf_size = (size / 3 + (size % 3 != 0)) * 4 + 1;
// 	char * outbuf = MDF_CALLOC(out_buf_size, 1);
// 	ret = mbedtls_base64_encode((unsigned char *)outbuf, out_buf_size, &out_size, (const unsigned char *)data, size);
// 	if(ret != 0){
// 		MDF_LOGE("b64 encode fail %d", ret);
// 		MDF_FREE(outbuf);
// 		return MDF_FAIL;
// 	}

// 	char * resp_data = NULL;
// 	int resp_size;
// 	mlink_json_pack(&resp_data, "type", "dt_report");
// 	if(ch == 0){
// 		mlink_json_pack(&resp_data, "cid", 102);
// 	}else if(ch ==1){
// 		mlink_json_pack(&resp_data, "cid", 103);
// 	}
// 	resp_size = mlink_json_pack(&resp_data, "value", outbuf);

// 	ret = mlink_mqtt_write(&resp_data, resp_size);

// 	MDF_FREE(outbuf);
// 	MDF_FREE(resp_data);

// 	return ret;
// }

static void uart_event_task(void *pvParameters)
{
	dt_handle_t *dt_handler = (dt_handle_t *)pvParameters;
    uart_event_t event;
    // size_t buffered_size;
	int uart_num = g_dt_uart_num[dt_handler->ch];
	ESP_LOGI(TAG, "uart [%d] task start", uart_num);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(dt_handler->uart_queue, (void * )&event, portMAX_DELAY)) {
            bzero(dt_handler->rx_buf, BUF_SIZE);
            ESP_LOGI(TAG, "uart [%d] event:", uart_num);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.*/
                case UART_DATA:
                    ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                    uart_read_bytes(uart_num, dt_handler->rx_buf, event.size, portMAX_DELAY);
					if(dt_handler->recv_handle){
						dt_handler->recv_handle(dt_handler->rx_buf, event.size, dt_handler->ch);
					}
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow");
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(uart_num);
                    xQueueReset(dt_handler->uart_queue);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full");
                    // If buffer full happened, you should consider encreasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(uart_num);
                    xQueueReset(dt_handler->uart_queue);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }
    }
    vTaskDelete(NULL);
}
esp_err_t dt_uart_send_data(uint8_t ch, const char * data, size_t inlen)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);
	MDF_PARAM_CHECK(data!=NULL);
	MDF_PARAM_CHECK(inlen>0);
	
	int ret = ESP_OK;
	// b64 decode
	size_t decode_size;
	uint8_t *decode_buf = MDF_CALLOC(inlen, 1);
	if(0 != mbedtls_base64_decode((unsigned char *)decode_buf, inlen, &decode_size, (const unsigned char *)data, inlen)){
		MDF_LOGE("mbedtls_base64_decode fail");
		ret = ESP_FAIL;
		goto FREE_MEM;
	}

	dt_handle_t *dt_h = &g_dt_handler[ch];
	int uart_num = g_dt_uart_num[dt_h->ch];
	MDF_LOGI("uart [%d] send %d",uart_num, decode_size);
	if(0 > uart_write_bytes(uart_num, (const char *) decode_buf, decode_size)){
		ret = ESP_FAIL;
	}
FREE_MEM:
	MDF_FREE(decode_buf);	

	return ret;
}

esp_err_t dt_uart_send_bytes(uint8_t ch, const char * data, size_t inlen)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);
	MDF_PARAM_CHECK(data!=NULL);
	MDF_PARAM_CHECK(inlen>0);
	
	int ret = ESP_OK;
	dt_handle_t *dt_h = &g_dt_handler[ch];
	int uart_num = g_dt_uart_num[dt_h->ch];
	MDF_LOGD("uart [%d] send %d",uart_num, inlen);
	if(0 > uart_write_bytes(uart_num, (const char *) data, inlen)){
		ret = ESP_FAIL;
	}

	return ret;
}


esp_err_t dt_uart_set_enable( uint8_t ch, int value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);
	dt_channel_store_t *cfg = &g_dt_cfg[ch];

	return ESP_FAIL;
}

esp_err_t dt_uart_get_enable( uint8_t ch, int *value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);
	dt_channel_store_t *cfg = &g_dt_cfg[ch];

	*value = 1;
	return ESP_OK;
}

esp_err_t dt_uart_set_baud_rate( uint8_t ch, int value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	if(ESP_OK != uart_set_baudrate(g_dt_uart_num[ch], value))
		return ESP_FAIL;
	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	cfg->baud_rate = value;
	dt_save_config_info( ch, cfg);
	return ESP_OK;
}

esp_err_t dt_uart_get_baud_rate( uint8_t ch, int *value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);
	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	*value = cfg->baud_rate;
	return ESP_OK;
}

esp_err_t dt_uart_set_data_bits( uint8_t ch, int value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	if(ESP_OK != uart_set_word_length(g_dt_uart_num[ch], value))
		return ESP_FAIL;
	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	cfg->data_bits = value;
	dt_save_config_info( ch, cfg);
	return ESP_OK;
}

esp_err_t dt_uart_get_data_bits( uint8_t ch, int *value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	*value = cfg->data_bits;
	return ESP_OK;
}

esp_err_t dt_uart_set_stop_bits( uint8_t ch, int value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	if(ESP_OK != uart_set_stop_bits(g_dt_uart_num[ch], value))
		return ESP_FAIL;
	
	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	cfg->stop_bits = value;
	dt_save_config_info( ch, cfg);
	return ESP_OK;

}

esp_err_t dt_uart_get_stop_bits( uint8_t ch, int *value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	*value = cfg->stop_bits;
	return ESP_OK;
}

esp_err_t dt_uart_set_parity( uint8_t ch, int value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	if(ESP_OK != uart_set_parity(g_dt_uart_num[ch], value))
		return ESP_FAIL;

	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	cfg->parity = value;
	dt_save_config_info( ch, cfg);
	return ESP_OK;
}

esp_err_t dt_uart_get_parity( uint8_t ch, int *value)
{
	MDF_PARAM_CHECK(ch < DT_MAX_CHANNEL);

	dt_channel_store_t *cfg = &g_dt_cfg[ch];
	*value = cfg->parity;
	return ESP_OK;
}

esp_err_t dt_uart_config( dt_handle_t *dt_h, dt_config_t *dt_config)
{
	MDF_PARAM_CHECK(dt_config!=NULL);
	MDF_PARAM_CHECK(dt_config->enable > 0);
	MDF_PARAM_CHECK(dt_config->mode >= 0);
	MDF_PARAM_CHECK(dt_config->data_bits >= 0);
	MDF_PARAM_CHECK(dt_config->stop_bits > 0);
	MDF_PARAM_CHECK(dt_config->parity >= 0);

	MDF_LOGI("Dt uart Tx io:%d, Rx io:%d, Rts io:%d", dt_config->tx_io_num, dt_config->rx_io_num, dt_config->rts_io_num);

	const int uart_num = dt_config->uart_num;
	dt_h->uart_num = uart_num;
    uart_config_t uart_config = {
        .baud_rate = dt_config->baud_rate,
        .data_bits = dt_config->data_bits,
        .parity = dt_config->parity,
        .stop_bits = dt_config->stop_bits,
        //.rx_flow_ctrl_thresh = 122,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };
	if(dt_config->mode == UART_MODE_RS485_HALF_DUPLEX){
		uart_config.rx_flow_ctrl_thresh = 122;
	}
    uart_driver_delete(uart_num);
    // Configure UART parameters
    ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
    ESP_ERROR_CHECK(uart_driver_install(uart_num, BUF_SIZE, BUF_SIZE, 5, &(dt_h->uart_queue), (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)));

    // Set UART pins as per KConfig settings
    ESP_ERROR_CHECK(uart_set_pin(uart_num, dt_config->tx_io_num, dt_config->rx_io_num, dt_config->rts_io_num, GPIO_NUM_NC));

    // Set RS485 half duplex mode
    ESP_ERROR_CHECK(uart_set_mode(uart_num, dt_config->mode));
	
    if(dt_config->mode == UART_MODE_RS485_HALF_DUPLEX){
	    // Set read timeout of UART TOUT feature
	    ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, RS485_READ_TOUT));
    }


	if(dt_h->rx_buf == NULL)
		dt_h->rx_buf = MDF_MALLOC(BUF_SIZE);

    if(dt_h->uart_task == NULL)
	    xTaskCreate(uart_event_task, "dt_task", 4*1024, dt_h, CONFIG_MDF_TASK_DEFAULT_PRIOTY+1, &dt_h->uart_task);
	
	dt_h->recv_handle = dt_config->recv_handle;
	dt_h->init = true;

	return MDF_OK;
}

esp_err_t dt_uart_deinit(dt_handle_t *dt_h)
{
	MDF_PARAM_CHECK(dt_h!=NULL);

	const int uart_num = dt_h->uart_num;
	if(dt_h->uart_task){
		vTaskDelete(dt_h->uart_task);
		dt_h->uart_task = NULL;
	}
	uart_driver_delete(uart_num);
	if(dt_h->rx_buf)
		MDF_FREE(dt_h->rx_buf);
	return ESP_OK;
}

static mdf_err_t mlink_handle_set_dt(mlink_handle_data_t *handle_data)
{
    mdf_err_t ret   = MDF_OK;
	dt_channel_store_t new_cfg = {0};

	int baud_rate;
	int data_bits;		/*!< UART byte size*/
	char parity; 		/*!< UART parity mode*/
	int stop_bits;		/*!< UART stop bits*/
	// int mode;
	char value_str[32];
	int ch;

    ret = mlink_json_parse(handle_data->req_data, "serial", &ch);
	MDF_ERROR_CHECK(ret != MDF_OK, ESP_FAIL, "Parse the json formatted string");
	if(ch >= 2) {
		return ESP_FAIL;
	}

	ret = mlink_json_parse(handle_data->req_data, "value", value_str);
	MDF_ERROR_CHECK(ret != MDF_OK, ESP_FAIL, "Parse the json formatted string");
	if(4 != sscanf(value_str, "%d %1d%1c%1d", &baud_rate, &data_bits, &parity, &stop_bits)) {
		return ESP_FAIL;
	}

	new_cfg.baud_rate = baud_rate;
	new_cfg.data_bits = data_bits-5;
	new_cfg.parity = parity == 'N'? 0 : parity == 'O'? 3 : 2;//0: none, 3: odd, 2: even
	new_cfg.stop_bits = stop_bits;
	uart_set_baudrate(g_dt_uart_num[ch], new_cfg.baud_rate);
	uart_set_word_length(g_dt_uart_num[ch], new_cfg.data_bits);
	uart_set_stop_bits(g_dt_uart_num[ch], new_cfg.stop_bits);
	uart_set_parity(g_dt_uart_num[ch], new_cfg.parity);
	dt_save_config_info( ch, &new_cfg);
    return MDF_OK;
}

static mdf_err_t mlink_handle_get_dt(mlink_handle_data_t *handle_data)
{
    mdf_err_t ret      = ESP_OK;
	char value_str[32];
	int ch;
	dt_channel_store_t cfg = {0};
	

    ret = mlink_json_parse(handle_data->req_data, "serial", &ch);
	MDF_ERROR_CHECK(ret != MDF_OK, ESP_FAIL, "Parse the json formatted string");
	if(ch >= 2) {
		return ESP_FAIL;
	}
	memcpy( &cfg, &g_dt_cfg[ch], sizeof(dt_channel_store_t));
	sprintf(value_str, "%d %1d%1c%1d", 
						cfg.baud_rate,
						cfg.data_bits+5,
						cfg.parity == 0? 'N' : cfg.parity == 3? 'O' : 'E',
						cfg.stop_bits);

	handle_data->resp_size = mlink_json_pack(&handle_data->resp_data, "serial", ch);
	handle_data->resp_size = mlink_json_pack(&handle_data->resp_data, "value", value_str);

    return ret;
}

mdf_err_t mlink_dt_load_store(void)
{
	dt_load_config_info(DT_CH_0_UART, &g_dt_cfg[0]);
	dt_load_config_info(DT_CH_1_UART, &g_dt_cfg[1]);

	return ESP_OK;
}

mdf_err_t mlink_dt_init(void)
{
	mlink_set_handle("set_serial", mlink_handle_set_dt);
	mlink_set_handle("get_serial", mlink_handle_get_dt);

	return ESP_OK;
}

